use std::{net::TcpListener, thread, sync::mpsc::Sender, time::SystemTime};

use crate::{server::{conf::ConfServer, func::CliFunction}, channel::{tcp::prelude::NrWriter, cmd::{self, Data, Cmd} }, cli::conf::{ConfCli, ConfCliPlus}};
use crate::channel::tcp::prelude::NrUReader;

use super::func::{Function, ResFunction};

/// 多线程启动终端监听
pub fn start(sx: &Sender<Box<dyn Function>>) {
    let sx_clone = sx.clone();
    thread::spawn(move || {
        let server_conf = ConfServer::get_conf().unwrap();
        println!("=====> socket启动端口: {:?}", server_conf.port_socket);
        let socket_listener = TcpListener::bind(("0.0.0.0", server_conf.port_socket)).unwrap();
        for socket_stream_result in socket_listener.incoming() {
            let sx_clone_clone = sx_clone.clone();
            thread::spawn(move || {
                let socket_stream = socket_stream_result.unwrap();
                let mut reader = NrUReader::from(&socket_stream).unwrap();
                let mut cli_bytes: Vec<u8> = vec![];
                let mut conf: Option<ConfCli> = Option::None;
                let start = SystemTime::now();
                loop {
                    if SystemTime::now().duration_since(start).unwrap().as_secs() > 30 {
                        return;
                    }
                    match reader.read(&mut cli_bytes) {
                        Ok(size) => {
                            if size > 0 {
                                let (datas, residual_bytes) = cmd::get_datas(cli_bytes.clone());
                                cli_bytes = residual_bytes;
                                for data in datas {
                                    match data.cmd {
                                        cmd::Cmd::CONF => {
                                            conf = serde_json::from_str(&String::from_utf8(data.data).unwrap()[..]).unwrap();
                                        },
                                        _ => {}
                                    }
                                }
                                match conf {
                                    Some(_) => { break },
                                    None => {},
                                }
                            }
                        },
                        Err(_) => { return },
                    }
                }

                let cid = conf.as_ref().unwrap().id;
                sx_clone_clone.send(Box::new(CliFunction::new_update(cid, Some(ConfCliPlus::new(conf.unwrap())), Some(NrWriter::from(&socket_stream))))).unwrap();
                cli_bytes.clear();
                loop {
                    let (success, datas) = read_message(&mut cli_bytes, &mut reader);
                    if !success {
                        break;
                    }
                    for data in datas {
                        handle(data, &sx_clone_clone);
                    }
                }
                sx_clone_clone.send(Box::new(CliFunction::new_remove(cid))).unwrap();
            });
        }
    });
}

fn read_message(cli_bytes: &mut Vec<u8>, reader: &mut NrUReader) -> (bool, Vec<Data>) {
    let mut datas = vec![];
    match reader.read(cli_bytes) {
        Ok(size) => {
            if size != 0 {
                let (mut ds, mut residual_bytes) = cmd::get_datas(cli_bytes.clone());
                cli_bytes.clear();
                cli_bytes.append(&mut residual_bytes);
                datas.append(&mut ds);
            }
            (true, datas)
        },
        Err(_) => { return (false, vec![]) }
    }
}

fn handle(data: Data, sx: &Sender<Box<dyn Function>>) {
    match data.cmd {
        Cmd::HEART => {
            heart_handle(&data);
        },
        Cmd::CONF => {
            conf_handle(&data, sx);
        },
        Cmd::Proxy2Server => {
            proxy_server_handle(data, sx);
        },
        _ => {}
    }
}

fn heart_handle(_: &Data) {

}

fn conf_handle(data: &Data, sx: &Sender<Box<dyn Function>>) {
    let c: ConfCli = serde_json::from_str(&String::from_utf8(data.data.clone()).unwrap()[..]).unwrap();
    sx.send(Box::new(CliFunction::new_update(data.cid, Some(ConfCliPlus::new(c)), None))).unwrap();
}

fn proxy_server_handle(data: Data, sx: &Sender<Box<dyn Function>>) {
    sx.send(Box::new(ResFunction::new(data.pid, data.data))).unwrap();
}